/*******************************************************************************
* 
* RiffReader parse RIFF (WAVE) file
* 
* 
******************************************************************************/
#include "riff-reader.h"

#define fourccRIFF 'FFIR'
#define fourccDATA 'atad'
#define fourccFMT ' tmf'
#define fourccWAVE 'EVAW'
#define fourccXWMA 'AMWX'
#define fourccDPDS 'sdpd'


namespace noria{ namespace xaudio
{
    HRESULT FindChunk(cbyte_ptr source, DWORD fourcc, DWORD & dwChunkSize, DWORD & dwChunkDataPosition);
    HRESULT ReadChunkData(cbyte_ptr source, void * buffer, DWORD buffersize, DWORD bufferoffset);

    RiffReader::RiffReader(void)
    {
    }


    RiffReader::~RiffReader(void)
    {
    }

    bool RiffReader::parse(const wstring& source)
    {
        return false;
    }

    bool RiffReader::parse(istream& source)
    {
        return false;
    }

    bool RiffReader::parse(cbinary_ref source)
    {
        byte_ptr p = &source[0];
        DWORD dwChunkSize;
        DWORD dwChunkPosition;
        DWORD filetype;

        // parse fourccRIFF
        FindChunk(p, fourccRIFF, dwChunkSize, dwChunkPosition);
        ReadChunkData(p, &filetype, sizeof(DWORD), dwChunkPosition);
        if (filetype != fourccWAVE)
            return false;

        // parse fourccFMT
        FindChunk(p, fourccFMT, dwChunkSize, dwChunkPosition);
		//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		// The following call will currupt memory of 
		//	'pMasteringVoice' and result app crash at the end
		//	of main()
		// Reason: unknown... 
		// Workaround: use CWaveFile to parse wave file instead
        //
        // PS: looks like this issue only happens on WIN8!!
		//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        ReadChunkData(p, &m_fmt, dwChunkSize, dwChunkPosition);

        // parse fourccDATA
        FindChunk(p, fourccDATA, dwChunkSize, dwChunkPosition);
        m_size = dwChunkSize;
        m_offset = p + dwChunkPosition;

        return true;
    }

    const WAVEFORMATEX* RiffReader::wavefmt() const
    {
        return &m_fmt;
    }

    size_t RiffReader::size() const
    {
        return m_size;
    }

    cbyte_ptr RiffReader::offset() const
    {
        return m_offset;
    }

    HRESULT FindChunk(cbyte_ptr source, DWORD fourcc, DWORD & dwChunkSize, DWORD & dwChunkDataPosition)
    {
        HRESULT hr = S_OK;
        //if( INVALID_SET_FILE_POINTER == SetFilePointer( hFile, 0, NULL, FILE_BEGIN ) )
        //    return HRESULT_FROM_WIN32( GetLastError() );

        DWORD dwChunkType;
        DWORD dwChunkDataSize;
        DWORD dwRIFFDataSize = 0;
        DWORD dwFileType;
        DWORD bytesRead = 0;
        DWORD dwOffset = 0;

        while (hr == S_OK)
        {
            //DWORD dwRead;
            //if( 0 == ReadFile( hFile, &dwChunkType, sizeof(DWORD), &dwRead, NULL ) )
            //    hr = HRESULT_FROM_WIN32( GetLastError() );
            memcpy((pointer)&dwChunkType, source, sizeof(DWORD));
            source += sizeof(DWORD);

            //if( 0 == ReadFile( hFile, &dwChunkDataSize, sizeof(DWORD), &dwRead, NULL ) )
            //    hr = HRESULT_FROM_WIN32( GetLastError() );
            memcpy((pointer)&dwChunkDataSize, source, sizeof(DWORD));
            source += sizeof(DWORD);

            switch (dwChunkType)
            {
            case fourccRIFF:
                dwRIFFDataSize = dwChunkDataSize;
                dwChunkDataSize = 4;
                //if( 0 == ReadFile( hFile, &dwFileType, sizeof(DWORD), &dwRead, NULL ) )
                //    hr = HRESULT_FROM_WIN32( GetLastError() );
                memcpy((pointer)&dwFileType, source, sizeof(DWORD));
                source += sizeof(DWORD);
                break;

            default:
                //if( INVALID_SET_FILE_POINTER == SetFilePointer( hFile, dwChunkDataSize, NULL, FILE_CURRENT ) )
                //return HRESULT_FROM_WIN32( GetLastError() );
                source += dwChunkDataSize;
            }

            dwOffset += sizeof(DWORD) * 2;
        
            if (dwChunkType == fourcc)
            {
                dwChunkSize = dwChunkDataSize;
                dwChunkDataPosition = dwOffset;
                return S_OK;
            }

            dwOffset += dwChunkDataSize;
        
            if (bytesRead >= dwRIFFDataSize) return S_FALSE;

        }

        return S_OK;
    }

    HRESULT ReadChunkData(cbyte_ptr source, void * buffer, DWORD buffersize, DWORD bufferoffset)
    {
        memcpy(buffer, source + bufferoffset, buffersize);
        return S_OK;
    }

}}